package com.hjx.movie.core.system.service.admin.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hjx.movie.common.utils.ResultType;
import com.hjx.movie.common.utils.exceptions.CustomException;
import com.hjx.movie.core.security.util.JwtAuthTokenUtil;
import com.hjx.movie.core.system.runner.SystemStaticData;
import com.hjx.movie.core.system.service.admin.IUserService;
import com.hjx.movie.persistence.system.mapper.IvyUserMapper;
import com.hjx.movie.persistence.system.model.IvyRole;
import com.hjx.movie.persistence.system.model.IvyUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.io.File;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>Title:</p>
 * <p>Description:</p>
 *
 * @author hjx
 * @date 2020/12/24 - 18:31
 */

@Service
@Transactional
@Slf4j
@CacheConfig(cacheNames = "IvyMovie:SpringCache:UserCache",keyGenerator = "cacheKeyGenerator")
public class UserService extends ServiceImpl<IvyUserMapper, IvyUser> implements IUserService {
    @Value("${file.disk}")
    private String disk;
    @Value("${file.path}")
    private String path;
    @Resource
    private SystemStaticData staticData;
    @Resource
    PasswordEncoder passwordEncoder;
    @Resource
    RedisTemplate<String,Object> redisTemplate;
    @Resource
    JwtAuthTokenUtil jwtAuthTokenUtil;

    //新增一个用户  beforeInvocation = true先把缓存中的数据进行删除
    @CacheEvict(value = "IvyMovie:SpringCache:UserCache",key = "#root.targetClass.name+':list:'",beforeInvocation = true)
    @Override
    public boolean insertUser(IvyUser user){
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return super.save(user);
    }
    //修改一个用户信息 修改操作需要把对应用户的缓存给清除掉
    @Caching(evict={
            @CacheEvict(value = "IvyMovie:SpringCache:UserCache",key = "#root.targetClass.name+':getById:'+#user.getUserId().toString()",beforeInvocation = true),
            @CacheEvict(value = "IvyMovie:SpringCache:UserCache",key = "#root.targetClass.name+':list:'",beforeInvocation = true),
            @CacheEvict(value="IvyMovie:SpringCache:AuthCache",
                    key = "'com.hjx.movie.core.security.service.impl.AuthService:findUserById:'+#user.getUserId().toString()",
                    beforeInvocation = true)
    })
    @Override
    public boolean updateUser(IvyUser user){
        Assert.notNull(user.getUserId(),"修改操作必须要传入需要修改的用户标识");
        //这个修改方法不进行修改密码操作
        if (StringUtils.isNoneBlank(user.getPassword())){
            user.setPassword("");
        }
        return updateById(user);

    }
    //删除一个用户 删除操作需要把对应用户的缓存给清除掉
    @Caching(evict={
            @CacheEvict(value = "IvyMovie:SpringCache:UserCache",key = "#root.targetClass.name+':getById:'+#userId.toString()",beforeInvocation = true),
            @CacheEvict(value = "IvyMovie:SpringCache:UserCache",key = "#root.targetClass.name+':list:'",beforeInvocation = true),
            @CacheEvict(value="IvyMovie:SpringCache:AuthCache",
                    key = "'com.hjx.movie.core.security.service.impl.AuthService:findUserById:'+#userId.toString()", beforeInvocation = true)
    })
    @Override
    public boolean deleteUser(Long userId) {
        Assert.notNull(userId,"需要删除的用户标识不能为空");
        return removeById(userId);
    }

    /**
     * 管理员进行密码修改
     * @param adminId 当前操作的管理员标识
     * @param adminPassword 管理员的密码
     * @param userId 修改的用户的标识
     * @param password 用户的新密码
     * @return 是否修改成功
     */
    @Override
    public boolean adminUpdatePassword(Long adminId,String adminPassword,Long userId,String password){
        //管理员修改密码
        IvyUser admin = super.getById(adminId);
        Assert.notNull(admin,"查询不到管理员帐号");
        // 比对管理员密码
        if (passwordEncoder.matches(adminPassword,admin.getPassword())){
            IvyUser user = super.getById(userId);
            Assert.notNull(user,"查询不到用户");
            return this.updatePassword(user,password);
        }else {
            throw new CustomException(ResultType.USER_INPUT_ERROR,"管理员的密码不正确");
        }
    }

    /**
     * 用户进行密码修改
     * @param userId 用户标识
     * @param oldPassword 用户的旧密码
     * @param password 用户的新密码
     * @return 是否修改成功
     */
    @Override
    public boolean userUpdatePassword(Long userId, String oldPassword, String password) {
        IvyUser user = super.getById(userId);
        Assert.notNull(user,"查询不到用户");
        if (passwordEncoder.matches(oldPassword,user.getPassword())) {
            return this.updatePassword(user,password);
        }else {
            throw new CustomException(ResultType.USER_INPUT_ERROR,"当前使用的密码不正确");
        }
    }

    /**
     * 实际进行修改密码操作
     * @param user 修改密码的用户
     * @param password 新密码
     * @return 是否修改成功
     */
    public boolean updatePassword(IvyUser user,String password){
        user.setPassword(passwordEncoder.encode(password));
        if (updateById(user)){
            Boolean result = true;
            String key = jwtAuthTokenUtil.getCacheTokenName(user.getUserId().toString());
            //修改成功 踢掉登录状态
            if(redisTemplate.opsForValue().get(key)!=null){
                result = redisTemplate.delete(key);
            }
            if (result!=null&&result){
                return true;
            }else {
                throw new CustomException(ResultType.SYSTEM_ERROR,"修改失败");
            }
        }
        return false;
    }
    /**
     * 获取一个用户信息 不会查询出密码
     * @param uid 用户标识
     * @return IvyUser对象
     */
    @Cacheable(unless="#result == null")
    public IvyUser getById(String uid){
        if (StringUtils.isNotBlank(uid)){
            IvyUser user = super.getById(uid);
            if (user!=null){
                user.setPassword("");
                return user;
            }else {
                throw new CustomException(ResultType.USER_INPUT_ERROR,"查询的用户不存在");
            }
        }else {
            throw new CustomException(ResultType.USER_INPUT_ERROR,"查询的用户不存在");
        }
    }

    /**
     * 查询全部的用户，但是不会把密码查询出来
     * @return 用户列表
     */
    @Cacheable(unless="#result == null")
    @Override
    public List<IvyUser> list(){
        QueryWrapper<IvyUser> wrapper = new QueryWrapper<>();
        //查询忽略密码字段
        wrapper.select(IvyUser.class,user->!user.getColumn().equals("password"));
        return super.list(wrapper);
    }

    @Override
    public List<IvyUser> queryUserLike(String s) {
        return lambdaQuery().like(IvyUser::getUserId,s)
                .or().like(IvyUser::getUsername,s)
                .or().like(IvyUser::getEmail,s)
                .or().like(IvyUser::getPhone,s)
                .list();
    }

    public String getUserHeadRealPath(Long id){
        return disk + File.separator + path + File.separator + staticData.getStaticValue("FOLDER_USER_HEAD") + File.separator + id;
    }

}
